/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.admin.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springblade.common.cache.DictCache;
import org.springblade.common.utils.CommonUtil;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tenant.annotation.TenantIgnore;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.admin.dto.ElevatorScheduleLabelListDTO;
import org.springblade.modules.admin.dto.plan.BatchModifyPlanUserDTO;
import org.springblade.modules.admin.entity.*;
import org.springblade.modules.admin.enums.*;
import org.springblade.modules.admin.service.*;
import org.springblade.modules.admin.vo.*;
import org.springblade.modules.admin.mapper.MaintainPlanConfigMapper;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.modules.admin.vo.defert.PlanConfigVo;
import org.springblade.modules.admin.vo.feishu.LarkMaintainPlanConfigVO;
import org.springblade.modules.admin.vo.openapi.SidaElevatorSchedulesVO;
import org.springblade.modules.admin.vo.task.ElevatorContractVo;
import org.springblade.modules.admin.vo.task.PlanCheckParam;
import org.springblade.modules.admin.vo.task.PlanTipVO;
import org.springblade.modules.admin.vo.task.SpeedPlanParam;
import org.springblade.modules.system.entity.TenantConfig;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.service.IUserService;
import org.springblade.modules.system.service.TenantConfigService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 保养计划配置 服务实现类
 *
 * @author ysq
 * @since 2022-03-09
 */
@Service
public class MaintainPlanConfigServiceImpl extends BaseServiceImpl<MaintainPlanConfigMapper, MaintainPlanConfig> implements IMaintainPlanConfigService {

	@Lazy
	@Autowired
	private IMaintainPlanContentService planContentService;

	@Lazy
	@Autowired
	private IContractAgreeService contractAgreeService;
	@Autowired
	private TenantConfigService tenantConfigService;
	@Lazy
	@Autowired
	private IMaintainPlanContentUserService planContentUserService;
	@Autowired
	private IUserService userService;
	@Autowired
	private IElevatorExtService elevatorExtService;

	@Override
	public IPage<MaintainPlanConfigVO> selectMaintainPlanConfigPage(IPage<MaintainPlanConfigVO> page, MaintainPlanConfigVO maintainPlanConfig) {
		maintainPlanConfig.setTenantId(AuthUtil.getTenantId());

		Integer integer = Convert.toInt(maintainPlanConfig.getHasPlanType(), -1);
		if (integer == 1) {
			List<ElevatorContract> eles = contractAgreeService.notPlanEleHasContract(DateUtil.yesterday());
			List<Long> eleIds = eles.stream().map(ElevatorContract::getElevatorId).distinct().collect(Collectors.toList());
			maintainPlanConfig.setEleIds(eleIds);
		} else if (integer == 2) {
			List<ElevatorContract> eles = contractAgreeService.notPlanEleHasContract(null);
			List<Long> eleIds = eles.stream().map(ElevatorContract::getElevatorId).distinct().collect(Collectors.toList());
			maintainPlanConfig.setEleIds(eleIds);
		}
		List<MaintainPlanConfigVO> list = baseMapper.selectMaintainPlanConfigPage(page, maintainPlanConfig);
		// 在保状态
		List<Integer> maintainStatusList = Arrays.asList(ElevatorMaintainStatusEnums.CONTRACT_IN_TIME.getId(), ElevatorMaintainStatusEnums.CONTRACT_OUT_TIME.getId(), ElevatorMaintainStatusEnums.DIS_ENABLE.getId(), ElevatorMaintainStatusEnums.OUT_TIME_STOP.getId(), ElevatorMaintainStatusEnums.OUT_TIME_END.getId(), ElevatorMaintainStatusEnums.OUT_TIME_END_HAS_NEXT.getId());
		for (MaintainPlanConfigVO planConfig : list) {
			// 若在保
			if (maintainStatusList.contains(planConfig.getMaintainStatus())) {
				Integer useType = planConfig.getUseType();
				if (!Func.equalsSafe(useType, 0)) {
					continue;
				}

				/**
				 * 若年审梯，保养合规状态：
				 * 正常：今日 < 当前逾期临界日期
				 * 明天即将违规：今日 = 当前逾期临界日期
				 * 已违规：今日 > 当前逾期临界日期
				 */
				int overdueCompare = DateUtil.compare(DateUtil.date(), planConfig.getOverdueDate(), "yyyy-MM-dd");
				if (overdueCompare < 0) {
					planConfig.setComplianceStatus(ComplianceStatusEnum.NORMAL.getId());
				} else if (overdueCompare == 0) {
					planConfig.setComplianceStatus(ComplianceStatusEnum.VIOLATING.getId());
				} else {
					planConfig.setComplianceStatus(ComplianceStatusEnum.VIOLATED.getId());
				}

				/**
				 * 若年审梯，下次保养计划是否存在逾期风险：
				 * 否：下次保养计划日期 <= 当前逾期临界日期
				 * 是：下次保养计划日期 > 当前逾期临界日期
				 */
				if (planConfig.getNextPlanDate() != null) {
					int riskCompare = DateUtil.compare(planConfig.getNextPlanDate(), planConfig.getOverdueDate(), "yyyy-MM-dd");
					if (riskCompare <= 0) {
						planConfig.setIsOverdueRisk(false);
					} else {
						planConfig.setIsOverdueRisk(true);
					}
				}
			}
		}
		return page.setRecords(list);
	}

	@Override
	public List<Map<Long, String>> getBuilidingList(PlanConfigSearchVO search) {
		return baseMapper.getBuilidingList(search);
	}

	@Override
	public List<Map<Long, String>> getElevatorList(PlanConfigSearchVO search) {
		return baseMapper.getElevatorList(search);
	}

	@Override
	public List<Map<Long, String>> getModeTypeList(PlanConfigSearchVO search) {
		return baseMapper.getModeTypeList(search);
	}

	@Override
	public List<TaskPlanListVO> getTaskPlanList(String keyword) {
		return baseMapper.getTaskPlanList(AuthUtil.getTenantId(), keyword);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean speedCreatePlan(SpeedPlanParam speedPlanParam) {
		// 1、开始时间与结束时间 >= 当前时间 && 首次保养时间 >= 开始时间
		if (DateUtil.between(speedPlanParam.getStartTime(), DateUtil.date(), DateUnit.DAY, false) > 0
			|| DateUtil.between(speedPlanParam.getEndTime(), DateUtil.date(), DateUnit.DAY, false) > 0
			|| DateUtil.between(speedPlanParam.getFirstTime(), speedPlanParam.getStartTime(), DateUnit.DAY, false) > 0) {
			throw new ServiceException("日期非法, 开始时间与结束时间需要大于当前时间且首次保养时间需要大于开始时间!");
		}

		// 2、校验电梯与模板年审类型是否一致
		planContentService.elevatorPlanUseTypeCheck(Func.toLongList(speedPlanParam.getElevatorIds()), speedPlanParam.getTaskPlanId());

		// 3、检验任务计划有无变更
		planContentService.taskTemplateCheck(speedPlanParam.getElevatorIds(), speedPlanParam.getTaskPlanId());

		// 4、删除该时间区间所有未开始的任务
		planContentService.deleteDateIntervalTask(Func.toLongList(speedPlanParam.getElevatorIds()), speedPlanParam.getStartTime(), speedPlanParam.getEndTime());

		// 5、更新计划配置
		MaintainPlanConfig planConfig = new MaintainPlanConfig();
		BeanUtils.copyProperties(speedPlanParam, planConfig);
		baseMapper.update(planConfig, Wrappers.<MaintainPlanConfig>lambdaUpdate().in(MaintainPlanConfig::getElevatorId, Func.toLongList(speedPlanParam.getElevatorIds())));

		// 6、根据任务计划生成任务
		planContentService.speedCreatePlanBatch(speedPlanParam);

		return true;
	}

	@Override
	public List<Map<Long, String>> getTemplateByElevatorId(Long elevatorId) {
		String tenantId = BladeConstant.ADMIN_TENANT_ID.equals(AuthUtil.getTenantId()) ? null : AuthUtil.getTenantId();
		return baseMapper.getTemplateByElevatorId(elevatorId, tenantId);
	}

	@Override
	public PlanConfigStatisticsVO planConfigStatistics(int intervalMonth) {
		PlanConfigStatisticsVO statisticsVO = new PlanConfigStatisticsVO();
		List<MaintainPlanConfigVO> list = baseMapper.planConfigStatistics(intervalMonth, null);
		long buildingTotal = list.stream().map(t -> t.getBuildingId()).distinct().count();
		statisticsVO.setBuildingTotal(buildingTotal);
		long elevatorTotal = list.stream().map(t -> t.getElevatorId()).count();
		statisticsVO.setElevatorTotal(elevatorTotal);
		long notPlanBuildingTotal = list.stream().filter(t -> t.getPlanTotal() == 0).map(t -> t.getBuildingId()).distinct().count();
		statisticsVO.setNotPlanBuildingTotal(notPlanBuildingTotal);
		long notPlanElevatorTotal = list.stream().filter(t -> t.getPlanTotal() == 0).map(t -> t.getElevatorId()).count();
		statisticsVO.setNotPlanElevatorTotal(notPlanElevatorTotal);
		statisticsVO.setNotPlanTaskEleTotal(baseMapper.notPlanTaskElevatorTotal());
		long normalEleTotal = list.stream().filter(t -> t.getIsStop() == 1).map(t -> t.getElevatorId()).distinct().count();
		statisticsVO.setNormalEleTotal(normalEleTotal);
		long stopEleTotal = list.stream().filter(t -> t.getIsStop() == 2).map(t -> t.getElevatorId()).distinct().count();
		statisticsVO.setStopEleTotal(stopEleTotal);
		statisticsVO.setScrapELeTotal(0L);
		statisticsVO.setCancelEleTotal(0L);
		statisticsVO.setReportStopELeTotal(0L);
		return statisticsVO;
	}

	@Override
	public PlanCreateStatisticsVO planConfigStatisticsPlus(int maintainStatus) {
		PlanCreateStatisticsVO statisticsVO = new PlanCreateStatisticsVO();
		// 在保
		if (maintainStatus == 0) {
			// 在保状态
			List<Integer> maintainStatusList = Arrays.asList(ElevatorMaintainStatusEnums.CONTRACT_IN_TIME.getId(), ElevatorMaintainStatusEnums.CONTRACT_OUT_TIME.getId(), ElevatorMaintainStatusEnums.DIS_ENABLE.getId(), ElevatorMaintainStatusEnums.OUT_TIME_END_HAS_NEXT.getId(), ElevatorMaintainStatusEnums.OUT_TIME_END.getId(), ElevatorMaintainStatusEnums.OUT_TIME_STOP.getId());
			List<MaintainPlanConfigVO> list = baseMapper.planConfigStatistics(3, maintainStatusList);
			// 三个月内未排期电梯数
			long notPlanThreeMonthTaskEleTotal = list.stream().filter(t -> t.getPlanTotal() == 0).map(t -> t.getElevatorId()).count();
			statisticsVO.setNotPlanThreeMonthTaskEleTotal(notPlanThreeMonthTaskEleTotal);
			// 从未排期电梯数
			statisticsVO.setNotPlanTaskEleTotal(baseMapper.notPlanTaskMaintainElevatorTotal());

			List<ElevatorContract> eles1 = contractAgreeService.notPlanEleHasContract(DateUtil.yesterday());
			List<ElevatorContract> eles2 = contractAgreeService.notPlanEleHasContract(null);
			statisticsVO.setNotPlanEleHasContractYesterday(eles1.size());
			statisticsVO.setNotPlanEleHasContract(eles2.size());
			// 下次保养计划排期存在逾期风险数
			long nextPlanOverdueRiskTotal = list.stream().filter(t -> {
				Integer useType = t.getUseType();
				if (Func.equalsSafe(useType, 0)) {
					if (t.getNextPlanDate() != null) {
						//逾期风险: 下次保养计划日期 > 当前逾期临界日期
						int riskCompare = DateUtil.compare(t.getNextPlanDate(), t.getOverdueDate(), "yyyy-MM-dd");
						return riskCompare > 0;
					}
				}
				return false;
			}).map(t -> t.getElevatorId()).count();
			statisticsVO.setNextPlanOverdueRiskTotal(nextPlanOverdueRiskTotal);
			// 其他剩余排期间隔存在逾期风险数
			statisticsVO.setOtherOverdueTotal(list.stream().filter(t -> t.getOtherOverdue() != null && t.getOtherOverdue() == 1).count());

			long nextPlanUserCountTotal = list.stream().filter(e -> Convert.toInt(e.getUseType(), -1).equals(0) && e.getNextUserCount() == 1).count();
			statisticsVO.setNextPlanUserCountTotal(nextPlanUserCountTotal);
		} else {
			// 脱保
			// 待清除未来保养排期数
			statisticsVO.setNeedClearFeaturePlanTotal(baseMapper.invalidMaintainPlanTask());
		}
		return statisticsVO;
	}

	@Override
	public boolean editPlanConfig(SpeedPlanParam speedPlanParam) {
		planContentService.taskTemplateCheck(speedPlanParam.getElevatorIds(), speedPlanParam.getTaskPlanId());
		MaintainPlanConfig planConfig = new MaintainPlanConfig();
		BeanUtils.copyProperties(speedPlanParam, planConfig);
		int res = baseMapper.update(planConfig, Wrappers.<MaintainPlanConfig>lambdaUpdate().in(MaintainPlanConfig::getElevatorId, Func.toLongList(speedPlanParam.getElevatorIds())));
		return res > 0;
	}

	@Override
	public List<PlanTipVO> planCheck(PlanCheckParam planCheckParam) {
		List<PlanTipVO> planTipList = new ArrayList<>();

		// 根据范围生成所有日期
		LinkedList<Date> planDates = new LinkedList<>();
		Date tempDate = planCheckParam.getStartTime();
		do {
			planDates.add(tempDate);
			tempDate = DateUtil.offsetDay(tempDate, 1);
		} while (DateUtil.between(tempDate, planCheckParam.getEndTime(), DateUnit.DAY, false) >= 0);

		List<Long> elevatorIds = Func.toLongList(planCheckParam.getElevatorIds());
		for (Long elevatorId : elevatorIds) {
			int inContract = 0;
			List<ElevatorContractVo> contractList = baseMapper.getAllContractsByElevatorId(elevatorId);
			if (Func.isNotEmpty(contractList)) {
				for (Date planDate : planDates) {
					for (ElevatorContractVo contract : contractList) {
						boolean isIn = DateUtil.isIn(planDate, contract.getContractBeginTime(), contract.getContractEndTime());
						if (isIn) {
							inContract++;
							break;
						}
					}
				}
			}

			PlanTipVO planTipVO = new PlanTipVO();
			planTipVO.setElevatorId(elevatorId);
			planTipVO.setDayTotal(planDates.size());
			planTipVO.setNotInContract(planDates.size() - inContract);
			planTipList.add(planTipVO);
		}
		return planTipList;
	}

	@Override
	public List<PlanConfigVo> getPlanConfigVo(List<Long> elevatorIds) {
		return baseMapper.getPlanConfigVo(elevatorIds);
	}

	@Override
	public void down(HttpServletResponse response, MaintainPlanConfigVO maintainPlanConfig) throws IOException {
		ExcelWriter excelWriter = null;
		ServletOutputStream outputStream = response.getOutputStream();
		try {
			List<List<String>> rows = new ArrayList<>();
			List<String> title = CollUtil.newArrayList
				("项目名称", "楼栋号", "项目地址", "单位内编号", "梯型式", "外包情况", "年审类型", "电梯所属维保组", "保养状态", "电梯状态", "年审梯保养合规状态",
					"违规天数", "上次维保签字日期", "下次保养计划日期", "下次保养计划排期是否存在逾期风险", "其他剩余计划是否存在逾期风险", "有无未来保养排期计划",
					"下次保养计划执行人", "保养计划", "首次保养日期", "保养排期开始日期", "保养排期结束日期", "最后更新时间");
			rows.add(title);


			List<MaintainPlanConfigVO> list = this.selectMaintainPlanConfigPage(new Page(1, -1), maintainPlanConfig).getRecords();
			for (MaintainPlanConfigVO data : list) {
				List<String> item = new ArrayList<>();
				item.add(data.getBuildingName());
				item.add(data.getElevatorAddress());
				item.add(data.getAddress());
				item.add(data.getRegisterNumber());
				item.add(data.getModeName());
				item.add(data.getFromType() == null ? "-" : data.getFromType() == 1 ? "外包" : data.getFromType() == 2 ? "非外包" : "-");
				item.add(data.getUseType() == 0 ? "年审" : "非年审");
				item.add(data.getDeptName());
				if (data.getMaintainStatus() == ElevatorMaintainStatusEnums.NO_STATUS.getId()) {
					item.add("--");
				} else {
					item.add(ElevatorMaintainStatusEnums.getName(data.getMaintainStatus()));
				}
				item.add(data.getIsStop() == 1 ? "正常运行" : "停梯");
				String complianceStatus = "-";
				String dayCountStr = "-";
				switch (Convert.toInt(data.getComplianceStatus(), 0)) {
					case 1:
						complianceStatus = "正常";
						break;
					case 2:
						complianceStatus = "明天即将违规";
						break;
					case 3:
						if (Func.isNotEmpty(data.getOverdueDate())) {
							long dayCount = DateUtil.betweenDay(data.getOverdueDate(), DateUtil.date(), true);
							complianceStatus = "已违规";
							dayCountStr = String.valueOf(dayCount);
						}
						break;
					default:
				}
				item.add(complianceStatus);
				item.add(dayCountStr);
				item.add(Convert.toStr(DateUtil.format(data.getPreviousPlanDate(), "yyyy-MM-dd")));
				item.add(Convert.toStr(DateUtil.format(data.getNextPlanDate(), "yyyy-MM-dd")));
				item.add(Convert.toBool(data.getIsOverdueRisk(), false) ? "是" : "否");
				item.add(Convert.toBool(data.getOtherOverdue(), false) ? "是" : "否");
				item.add(data.getIsPlan() == 0 ? "无" : "有");
				item.add(data.getNextUserNames());
				item.add(data.getTemplatePlanName());
				item.add(Convert.toStr(DateUtil.format(data.getFirstTime(), "yyyy-MM-dd")));
				item.add(Convert.toStr(DateUtil.format(data.getStartTime(), "yyyy-MM-dd")));
				item.add(Convert.toStr(DateUtil.format(data.getEndTime(), "yyyy-MM-dd")));
				item.add(Convert.toStr(DateUtil.format(data.getUpdateTime(), "yyyy-MM-dd hh:mm:ss")));
				rows.add(item);
			}
			String fileName = DateUtil.format(new Date(), "yyyyMMddHHmmss") + ".xlsx";
			CommonUtil.setResponseHeader(response, fileName);
			excelWriter = ExcelUtil.getBigWriter(rows.size());
			excelWriter.write(rows, true);
			excelWriter.flush(outputStream, true);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (excelWriter != null) {
				excelWriter.close();
			}
			outputStream.close();
		}
	}

	@Override
	public List<MaintainPlanConfig> listAll() {
		return baseMapper.listAll();
	}

	/**
	 * 飞书电梯合规记录表
	 *
	 * @return 即将同步到飞书的结果
	 */
	@Override
	@TenantIgnore
	public List<LarkMaintainPlanConfigVO> getLarkMaintainPlanConfigVOList() {
		return baseMapper.getLarkMaintainPlanConfigVOList();
	}

	@Override
	public List<Map<String, Object>> getBuildingAllList(PlanConfigSearchVO search) {
		List<Map<String, Object>> result = baseMapper.getBuildingAllList(search);
//		result.forEach(e -> {
//			if(Func.isNotEmpty(e.get("type"))){
//				e.put("buildingType", DictCache.getValue("building_type",String.valueOf(e.get("type"))));
//			}
//		});
		return result;
	}

	@Override
	public List<SidaElevatorSchedulesVO> getElevatorSchedulesListByTenantIdAndTime(String tenantId,
																				   Date lastMaintainStartTime, Date lastMaintainEndTime,
																				   Date previousPlanDateStartTime, Date previousPlanDateEndTime,
																				   Date nextPlanDateStartTime, Date nextPlanDateEndTime,
																				   Date overdueDateStartTime, Date overdueDateEndTime) {
		return baseMapper.getElevatorSchedulesListByTenantIdAndTime(tenantId,
			lastMaintainStartTime, lastMaintainEndTime,
			previousPlanDateStartTime, previousPlanDateEndTime,
			nextPlanDateStartTime, nextPlanDateEndTime,
			overdueDateStartTime, overdueDateEndTime);
	}

	@Override
	public Map<String, List<VerifyModifyPlanUserResultVO>> verifyModifyPlanUser(BatchModifyPlanUserDTO userDTO) {
		// 获取保养工单
		List<VerifyModifyPlanUserResultVO> planList = planContentService.selectVerifyModifyPlanUser(userDTO);
		List<VerifyModifyPlanUserResultVO> errorList = new ArrayList<>();
		List<VerifyModifyPlanUserResultVO> correctList = new ArrayList<>();
		Map<String, List<VerifyModifyPlanUserResultVO>> resultMap = new HashMap<>();
		if (Func.isEmpty(planList)) {
			resultMap.put("error", errorList);
			resultMap.put("correct", correctList);
			return resultMap;
		}
		TenantConfig tenantConfig = tenantConfigService.getTenantConfig(AuthUtil.getTenantId());
		// 是否强制双人 1-强制 2-不强制
		Integer cheMultiScheduleUser = Integer.valueOf(String.valueOf(tenantConfig.getConfig().get("cheMultiScheduleUser")));
		// 保养双人排期设置（多选逗号隔开） 1-年审梯 2-非年审梯
		String cheMultiSchedule = String.valueOf(tenantConfig.getConfig().get("cheMultiSchedule"));
		// 获取保养工单关联人员
		List<MaintainPlanContentUser> planContentUsers = planContentUserService.list(Wrappers.<MaintainPlanContentUser>lambdaQuery()
			.in(MaintainPlanContentUser::getPlanId, planList.stream().map(VerifyModifyPlanUserResultVO::getPlanId).collect(Collectors.toList())));
		// 获取所有人员信息
		List<Long> userIds = planContentUsers.stream().map(MaintainPlanContentUser::getUserId).collect(Collectors.toList());
		userIds.addAll(userDTO.getUserIds());
		List<User> userList = userService.listByIds(userIds);
		// 替换
		if (userDTO.getType().equals(1)) {
			planList.forEach(e -> {
				List<MaintainPlanContentUser> planUserList = planContentUsers.stream().filter(t -> t.getPlanId().equals(e.getPlanId())).collect(Collectors.toList());
				List<Long> planUserIds = planUserList.stream().map(MaintainPlanContentUser::getUserId).collect(Collectors.toList());
				e.setOldPlanUsers(userList.stream().filter(t -> planUserIds.contains(t.getId())).collect(Collectors.toList()));
				e.setNewPlanUsers(userList.stream().filter(t -> userDTO.getUserIds().contains(t.getId())).collect(Collectors.toList()));

				List<String> errorType = new ArrayList<>();
				if (cheMultiScheduleUser.equals(1) && cheMultiSchedule.contains(String.valueOf(e.getPlanAuditType()))) {
					if (e.getNewPlanUsers().size() < 2) {
						errorType.add("1");
					}
				}
				if (Func.isNotEmpty(errorType)) {
					e.setErrorType(String.join(",", errorType));
					errorList.add(e);
				} else {
					correctList.add(e);
				}
			});
			// 转移
		} else if (userDTO.getType().equals(2)) {
			planList.forEach(e -> {
				List<MaintainPlanContentUser> planUserList = planContentUsers.stream().filter(t -> t.getPlanId().equals(e.getPlanId())).collect(Collectors.toList());
				List<Long> planUserIds = planUserList.stream().map(MaintainPlanContentUser::getUserId).collect(Collectors.toList());
				if (planUserIds.contains(userDTO.getOldUserId())) {
					e.setOldPlanUsers(userList.stream().filter(t -> planUserIds.contains(t.getId())).collect(Collectors.toList()));
					e.setNewPlanUsers(userList.stream().filter(t -> (planUserIds.contains(t.getId()) || userDTO.getUserIds().contains(t.getId())) && !t.getId().equals(userDTO.getOldUserId())).collect(Collectors.toList()));

					List<String> errorType = new ArrayList<>();
					if (cheMultiScheduleUser.equals(1) && cheMultiSchedule.contains(String.valueOf(e.getPlanAuditType()))) {
						if (e.getNewPlanUsers().size() < 2) {
							errorType.add("1");
						}
					}
					if (Func.isNotEmpty(errorType)) {
						e.setErrorType(String.join(",", errorType));
						errorList.add(e);
					} else {
						correctList.add(e);
					}
				}
			});
			// 部分删除
		} else if (userDTO.getType().equals(3)) {
			planList.forEach(e -> {
				List<MaintainPlanContentUser> planUserList = planContentUsers.stream().filter(t -> t.getPlanId().equals(e.getPlanId())).collect(Collectors.toList());
				List<Long> planUserIds = planUserList.stream().map(MaintainPlanContentUser::getUserId).collect(Collectors.toList());
				e.setOldPlanUsers(userList.stream().filter(t -> planUserIds.contains(t.getId())).collect(Collectors.toList()));
				e.setNewPlanUsers(e.getOldPlanUsers().stream().filter(t -> !userDTO.getUserIds().contains(t.getId())).collect(Collectors.toList()));

				List<String> errorType = new ArrayList<>();
				if (cheMultiScheduleUser.equals(1) && cheMultiSchedule.contains(String.valueOf(e.getPlanAuditType()))) {
					if (e.getNewPlanUsers().size() < 2) {
						errorType.add("1");
					}
				}
				if (Func.isEmpty(e.getNewPlanUsers())) {
					errorType.add("2");
				}
				if (Func.isNotEmpty(errorType)) {
					e.setErrorType(String.join(",", errorType));
					errorList.add(e);
				} else {
					correctList.add(e);
				}
			});
		}

		resultMap.put("error", errorList);
		resultMap.put("correct", correctList);
		return resultMap;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public Boolean modifyPlanUser(List<VerifyModifyPlanUserResultVO> list) {
		if (Func.isEmpty(list)) {
			return Boolean.TRUE;
		}

		List<List<VerifyModifyPlanUserResultVO>> planPage = ListUtil.partition(list, 10);
		planPage.forEach(e -> {
			List<Long> planIds = e.stream().map(VerifyModifyPlanUserResultVO::getPlanId).collect(Collectors.toList());
			planContentUserService.remove(Wrappers.<MaintainPlanContentUser>lambdaQuery().in(MaintainPlanContentUser::getPlanId, planIds));
			List<MaintainPlanContentUser> planUsers = new ArrayList<>();
			e.forEach(t -> {
				t.getNewPlanUsers().forEach(k -> {
					MaintainPlanContentUser planUser = new MaintainPlanContentUser();
					planUser.setPlanId(t.getPlanId());
					planUser.setUserId(k.getId());
					planUsers.add(planUser);
				});
			});
			planContentUserService.saveBatch(planUsers);
		});
		return Boolean.TRUE;
	}

	@Override
	public List<MaintainPlanConfigVO> selectElevatorByPlanSchComRisks(String tenantId) {
		return baseMapper.selectElevatorByPlanSchComRisks(tenantId);
	}

	@Override
	public void updateElevatorScheduleLabel(String tenantId) {

		List<ElevatorScheduleLabelListDTO> elevatorList = baseMapper.selectElevatorScheduleLabelList(tenantId);
		if(Func.isNotEmpty(elevatorList)){
			List<ElevatorExt> resultList = new ArrayList<>();
			List<Long> elevatorIds = elevatorList.stream().map(ElevatorScheduleLabelListDTO::getElevatorId).collect(Collectors.toList());
			List<ElevatorExt> elevatorExts = elevatorExtService.list(Wrappers.<ElevatorExt>lambdaQuery().in(ElevatorExt::getElevatorId,elevatorIds));
			elevatorList.forEach(e -> {
				ElevatorExt elevatorExt = elevatorExts.stream().filter(t -> t.getElevatorId().equals(e.getElevatorId())).findFirst().orElse(new ElevatorExt());
				elevatorExt.setElevatorId(e.getElevatorId());
				List<Integer> scheduleLabelList = new ArrayList<>();

				// 电梯有无排期
				if(Func.isNotEmpty(e.getFuturePlanId())){
					scheduleLabelList.add(ElevatorScheduleLabelEnum.HAS_FUTURE_SCHEDULE.getCode());
				}else {
					scheduleLabelList.add(ElevatorScheduleLabelEnum.NO_FUTURE_SCHEDULE.getCode());
				}

				// 年审梯末次排期距合同到期日超15天 (即电梯合同期内的排期存在空挡)
				if(Func.isNotEmpty(e.getUseType()) && e.getUseType().equals(0)){
					if(e.getMaintainStatus().equals(ElevatorMaintainStatusEnums.CONTRACT_IN_TIME.getId())){
						if(Func.isNotEmpty(e.getLastDate()) && Func.isNotEmpty(e.getContractEndTime()) && DateUtil.compare(DateUtil.offsetDay(e.getLastDate(),15),e.getContractEndTime(),"yyyy-MM-dd") < 0){
							scheduleLabelList.add(ElevatorScheduleLabelEnum.LAST_PLAN_DATE_MOVE_15_DAYS.getCode());
						}
					}
				}

				// 有排期未续签合同
				if(Func.isNotEmpty(e.getFuturePlanId()) && (e.getMaintainStatus().equals(ElevatorMaintainStatusEnums.OUT_TIME_STOP.getId()) || e.getMaintainStatus().equals(ElevatorMaintainStatusEnums.OUT_TIME_END.getId()))){
					scheduleLabelList.add(ElevatorScheduleLabelEnum.HAS_FUTURE_SCHEDULE_AND_NO_FUTURE_CONTRACT.getCode());
				}

				// 超15天
				if(Func.isNotEmpty(e.getPreviousPlanDate()) && Func.isNotEmpty(e.getNextPlanDate())){
					if(DateUtil.compare(DateUtil.offsetDay(e.getPreviousPlanDate(),15),e.getNextPlanDate(),"yyyy-MM-dd") < 0){
						scheduleLabelList.add(ElevatorScheduleLabelEnum.MOVE_15_DAYS_SCHEDULE.getCode());
					}
				}

				// 维保中年审梯单人排期风险
				if(Func.isNotEmpty(e.getUseType()) && e.getUseType().equals(0)){
					if(e.getMaintainStatus().equals(ElevatorMaintainStatusEnums.CONTRACT_IN_TIME.getId())
						|| e.getMaintainStatus().equals(ElevatorMaintainStatusEnums.DIS_ENABLE.getId())
						|| e.getMaintainStatus().equals(ElevatorMaintainStatusEnums.OUT_TIME_STOP.getId())
						|| e.getMaintainStatus().equals(ElevatorMaintainStatusEnums.OUT_TIME_END.getId())
						|| e.getMaintainStatus().equals(ElevatorMaintainStatusEnums.OUT_TIME_END_HAS_NEXT.getId())
					){
						if(Func.isNotEmpty(e.getNextPlanUserCount()) && e.getNextPlanUserCount() == 1){
							scheduleLabelList.add(ElevatorScheduleLabelEnum.SOLO_SCHEDULE.getCode());
						}
					}
				}

				if(Func.isNotEmpty(scheduleLabelList)){
					elevatorExt.setScheduleLabel(scheduleLabelList.stream().map(String::valueOf).collect(Collectors.joining(",")));
				}else {
					elevatorExt.setScheduleLabel(null);
				}

				resultList.add(elevatorExt);
			});

			List<List<ElevatorExt>> list = ListUtil.partition(resultList,50);
			list.forEach(e -> elevatorExtService.saveOrUpdateBatch(e));
		}

	}
}
